﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.CompositeUI.Commands;
using Microsoft.Practices.CompositeUI.UIElements;
using SCSFContrib.CompositeUI.WPF.CommandAdapters;
using SCSFContrib.CompositeUI.WPF.UIElements;
using NUnit.Framework;
using WPFCABShell.Shell.Interface.Services.Command;
using WPFCABShell.Shell.Interface.Services.Menu;
using WPFCABShell.Shell.Services;
using WPFCABShell.Shell.Services.Command;
using WPFCABShell.Shell.Services.Menu;
using WPFCABShell.UnitTest.Shared;
using WPF = System.Windows.Controls;
using CAB = Microsoft.Practices.CompositeUI.Commands;

namespace WPFCABShell.UnitTest.Shell.Services.Menu
{
	[TestFixture]
	public sealed class MenuServiceTest : WPFCABShell.UnitTest.Shared.UnitTest
	{
		private TestableWorkItem _workItem;
		private CommandService _commandService;
		private MenuService _menuService;

		protected override void SetUpCore()
		{
			base.SetUpCore();

			_workItem = new TestableWorkItem();
			_commandService = new CommandService();
			_menuService = new MenuService(_workItem);

			_workItem.OnBuiltUp(null);

			//make sure the work item can adapt menus etc
			ICommandAdapterMapService commandAdapterMapService = _workItem.Services.Get<ICommandAdapterMapService>();
			commandAdapterMapService.Register(typeof(UIElement), typeof(UIElementCommandAdapter));

			IUIElementAdapterFactoryCatalog uiElementAdapterFactoryCatalog = _workItem.Services.Get<IUIElementAdapterFactoryCatalog>();
			uiElementAdapterFactoryCatalog.RegisterFactory(new ItemsControlUIAdapterFactory());
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Add_ShouldThrowIfTargetSiteIsNull()
		{
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand(cabCommand, "name", null);
			_menuService.Add(null, command, null, null, "siteName");
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Add_ShouldThrowIfCommandIsNull()
		{
			_menuService.Add("targetSiteName", null, null, null, "siteName");
		}

		[Test]
		[ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "No site named 'Not Found' could be found in the target WorkItem.")]
		public void Add_ShouldThrowIfTargetSiteNotFound()
		{
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand(cabCommand, "name", null);
			_menuService.Add("Not Found", command, null, null, "siteName");
		}

		[Test]
		public void Add_ShouldConfigureMenuItemCorrectly()
		{
			WPF.Menu menu = new WPF.Menu();
			string siteName = "MainMenu";
			_workItem.UIExtensionSites.RegisterSite(siteName, menu);
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand(cabCommand, "name", null);

			IMenuItem menuItem = _menuService.Add(siteName, command, 13, 8, null);
			Assert.AreSame(command, menuItem.Command);
			Assert.IsFalse(menuItem.IsChecked);
			Assert.AreEqual(13, GroupingItemsControlUIAdapter.GetGroupIndex(menuItem as DependencyObject));
			Assert.AreEqual(8, GroupingItemsControlUIAdapter.GetIndex(menuItem as DependencyObject));
		}

		[Test]
		public void Add_ShouldEnsureMenuItemIsHiddenIfNotACommandAndHasNoChildren()
		{
			WPF.Menu menu = new WPF.Menu();
			string targetSiteName = "MainMenu";
			string siteName = "SubMenu";
			_workItem.UIExtensionSites.RegisterSite(targetSiteName, menu);
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand("name", null);
			ICommand childCommand = _commandService.CreateCommand(cabCommand, "child", null);

			IMenuItem menuItem = _menuService.Add(targetSiteName, command, null, null, siteName);
			Assert.AreEqual(Visibility.Collapsed, (menuItem as UIElement).Visibility);
			IMenuItem childMenuItem = _menuService.Add(siteName, childCommand, null, null, null);
			Assert.AreEqual(Visibility.Visible, (menuItem as UIElement).Visibility);
			_menuService.Remove(childMenuItem);
			Assert.AreEqual(Visibility.Collapsed, (menuItem as UIElement).Visibility);
		}

		[Test]
		public void Add_ShouldAddMenuItemToTargetSite()
		{
			WPF.Menu menu = new WPF.Menu();
			string siteName = "MainMenu";
			_workItem.UIExtensionSites.RegisterSite(siteName, menu);
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand(cabCommand, "name", null);

			IMenuItem menuItem = _menuService.Add(siteName, command, null, null, null);
			Assert.IsNotNull(menuItem);
			Assert.IsTrue(menu.Items.Contains(menuItem));
		}

		[Test]
		public void Add_ShouldRegisterNewSiteIfSpecified()
		{
			WPF.Menu menu = new WPF.Menu();
			string siteName = "MainMenu";
			string newSiteName = "SubMenu";
			_workItem.UIExtensionSites.RegisterSite(siteName, menu);
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand(cabCommand, "name", null);

			Assert.IsFalse(_workItem.UIExtensionSites.Contains(newSiteName));
			IMenuItem menuItem = _menuService.Add(siteName, command, null, null, newSiteName);
			Assert.IsTrue(_workItem.UIExtensionSites.Contains(newSiteName));
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Remove_ShouldThrowIfMenuItemIsNull()
		{
			_menuService.Remove(null);
		}

		[Test]
		public void Remove_ShouldRemoveMenuItemFromContainer()
		{
			WPF.Menu menu = new WPF.Menu();
			string siteName = "MainMenu";
			_workItem.UIExtensionSites.RegisterSite(siteName, menu);
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand(cabCommand, "name", null);

			IMenuItem menuItem = _menuService.Add(siteName, command, null, null, null);
			Assert.IsTrue(menu.Items.Contains(menuItem));

			_menuService.Remove(menuItem);
			Assert.IsFalse(menu.Items.Contains(menuItem));
		}

		[Test]
		public void Remove_ShouldUnregisterSiteIfRelevant()
		{
			WPF.Menu menu = new WPF.Menu();
			string targetSiteName = "MainMenu";
			string siteName = "NewSite";
			_workItem.UIExtensionSites.RegisterSite(targetSiteName, menu);
			CAB.Command cabCommand = new CAB.Command();
			ICommand command = _commandService.CreateCommand(cabCommand, "name", null);

			Assert.IsFalse(_workItem.UIExtensionSites.Contains(siteName));
			IMenuItem menuItem = _menuService.Add(targetSiteName, command, null, null, siteName);
			Assert.IsTrue(menu.Items.Contains(menuItem));
			Assert.IsTrue(_workItem.UIExtensionSites.Contains(siteName));

			_menuService.Remove(menuItem);
			Assert.IsFalse(_workItem.UIExtensionSites.Contains(siteName));
		}
	}
}
